﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Criterion;
using Work.BL.Managers;
using Work.BL.POCOs;
using Work.DAL.Hibernate.Abstract;
using Work.DAL.Hibernate.Entities;
using Work.Tools.ObjectMapper;

namespace Work.BL.Hibernate.Managers
{
    public class HUserManager : IUserManager
    {
        #region Fields

        private readonly ICWSessionFactory _sessionFactory;
        private readonly IObjectMapper _objectMapper;

        #endregion

        #region Constructors

        public HUserManager(ICWSessionFactory sessionFactory, IObjectMapper objectMapper)
        {
            this._sessionFactory = sessionFactory;
            this._objectMapper = objectMapper;
        }

        #endregion

        #region IProjectManager Members

        public List<UserPOCO> GetUsers()
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                IList<User> users = session.CreateCriteria<User>().List<User>();
                return ConvertList(users);
            }
        }

        public UserPOCO GetUserById(int userId)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                User user = session.Get<User>(userId);
                return ConvertItem(user);
                //return _objectMapper.Map<User, UserPOCO>(user);
            }
        }

        public UserPOCO Insert(UserPOCO userPoco)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                userPoco.Name = userPoco.Name.ToLower();
                userPoco.Email = userPoco.Email.ToLower();
                User user = ConvertItem(userPoco);
                //User user = _objectMapper.Map<UserPOCO, User>(userPoco);
                session.Save(user);
                return ConvertItem(user);
            }
        }

        public int GetUserCount()
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                int rowCount = session.CreateCriteria<User>()
                    .SetProjection(Projections.RowCount()).UniqueResult<int>();
                return rowCount;
            }
        }

        public List<UserPOCO> GetUsers(int startIndex, int maxCount)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {

                IList<User> users = session.CreateCriteria<User>()
                    .SetFirstResult(startIndex)
                    .SetMaxResults(maxCount)
                    .List<User>();
                return ConvertList(users);
            }
        }

        public UserPOCO Edit(UserPOCO userPoco)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                userPoco.Name = userPoco.Name.ToLower();
                userPoco.Email = userPoco.Email.ToLower();
                User user = _objectMapper.Map<UserPOCO, User>(userPoco);
                session.Update(user);
                session.Flush();
                return ConvertItem(user);
            }
        }

        public bool IsValid(string userName, string password)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                string _userName = userName.ToLower();
                return session.CreateCriteria<User>()
                    .List<User>().Any(u => u.Name == _userName && u.Password == password);
                
            }
        }

        public string[] GetUserRoles(string userName)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                string _userName = userName.ToLower();
                User user = session.CreateCriteria<User>().List<User>().First(u => u.Name == _userName);
                return user.Roles.Select(r => r.Name).ToArray();
            }
        }

        public void Delete(UserPOCO userPoco)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                User user = _objectMapper.Map<UserPOCO, User>(userPoco);
                session.Delete(user);
                session.Flush();
            }
        }

        public bool UniqueEmail(string email)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                string _email = email.ToLower();
                return session.CreateCriteria<User>().List<User>().Any(u => u.Email == _email);
            }
        }

        public bool UniqueUser(string userName)
        {
            using (ISession session = this._sessionFactory.CreateSession())
            {
                string _userName = userName.ToLower();
                return session.CreateCriteria<User>().List<User>().Any(u => u.Name == _userName);
            }
        }

        #endregion

        #region Helpers

        List<UserPOCO> ConvertList(IList<User> users)
        {
            return users
                    .Select(r => new UserPOCO()
                    {
                        Id = r.Id,
                        Name = r.Name,
                        Email = r.Email,
                        Password = r.Password,
                        Roles =
                            new List<RolePOCO>(
                            r.Roles.Select(p => new RolePOCO() { Id = p.Id, Name = p.Name }))
                    })
                    .ToList();
        } 

        UserPOCO ConvertItem(User user)
        {
            if(user.Roles == null)
            {
                return new UserPOCO()
                {
                    Id = user.Id,
                    Name = user.Name,
                    Email = user.Email,
                    Password = user.Password,
                    Roles = null
                };
            }
            return new UserPOCO()
                       {
                           Id = user.Id,
                           Name = user.Name,
                           Email = user.Email,
                           Password = user.Password,
                           Roles =
                               new List<RolePOCO>(user.Roles.Select(r => new RolePOCO()
                                                                             {
                                                                                 Id = r.Id,
                                                                                 Name = r.Name
                                                                             }))
                       };
        }

        User ConvertItem(UserPOCO userPoco)
        {
            if (userPoco.Roles == null)
            {
                return new User()
                {
                    Id = userPoco.Id,
                    Name = userPoco.Name,
                    Email = userPoco.Email,
                    Password = userPoco.Password,
                    Roles = null
                };
            }
            return new User()
            {
                Id = userPoco.Id,
                Name = userPoco.Name,
                Email = userPoco.Email,
                Password = userPoco.Password,
                Roles =
                    new List<Role>(userPoco.Roles.Select(r => new Role()
                    {
                        Id = r.Id,
                        Name = r.Name
                    }))
            };
        }

        #endregion
    }
}
